package com.cloudkinto.service.product.impl;

import cn.afterturn.easypoi.excel.entity.ExportParams;
import com.alibaba.fastjson.JSONObject;
import com.aliyun.oss.HttpMethod;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.cloudkinto.common.common.DateUtils;
import com.cloudkinto.common.constant.GlobalConstants;
import com.cloudkinto.common.constant.SysConstant;
import com.cloudkinto.common.exception.BizException;
import com.cloudkinto.common.utils.ExcelUtils;
import com.cloudkinto.common.utils.MathUtils;
import com.cloudkinto.common.utils.OkHttpUtils;
import com.cloudkinto.common.utils.StringsUtil;
import com.cloudkinto.common.utils.dict.StaticDict;
import com.cloudkinto.dao.*;
import com.cloudkinto.entity.*;
import com.cloudkinto.extentity.ProductOutDetailDto;
import com.cloudkinto.extentity.ProductOutDto;
import com.cloudkinto.extentity.ProductOutStockDto;
import com.cloudkinto.service.finance.vo.FianceChinaBankVo;
import com.cloudkinto.service.orderinput.OrderInputService;
import com.cloudkinto.service.orderoutput.OrderOutputService;
import com.cloudkinto.service.product.ProductOutService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import com.cloudkinto.common.web.PageResult;
import com.cloudkinto.common.web.SingleResult;

import com.cloudkinto.service.product.ProductStockFlowingService;
import com.cloudkinto.service.product.ProductStockRackService;
import com.cloudkinto.service.product.vo.*;
import com.cloudkinto.service.product.vo.exportVo.*;
import com.cloudkinto.service.product.vo.productout.StockMsgRes;
import com.cloudkinto.service.product.vo.rack.SendRes;
import com.cloudkinto.service.stock.StockLogService;
import com.cloudkinto.service.stock.StockRecordService;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.beans.factory.annotation.Autowired;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.temporal.WeekFields;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * <p>
 * service实现类
 * </p>
 *
 * @author hua
 * @since 2022-09-21
 */
@Service
@Transactional(rollbackFor = Exception.class)//事务回滚
public class ProductOutServiceImpl extends ServiceImpl<ProductOutDao, ProductOutDo> implements ProductOutService {
    @Autowired
    private ProductOutDao dao;
    @Autowired
    private OrderOutputService orderOutputService;
    @Autowired
    private OrderInputService orderInputService;
    @Autowired
    private ProductStockDao productStockDao;
    @Autowired
    private StockRecordDao mStockRecordDao;
    @Autowired
    private StockRecordService stockRecordService;
    @Autowired
    private StockLogService mStockLogService;
    @Autowired
    private ProductInfoDao productInfoDao;
    @Autowired
    private ShopDao shopDao;
    @Autowired
    private ProductOutRecordDao productOutRecordDao;
    @Autowired
    private StorageDao storageDao;
    @Autowired
    private ProductStockRackDao productStockRackDao;
    @Autowired
    private ProductStockRackService productStockRackService;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private StockPickUpDetailDao stockPickUpDetailDao;
    @Autowired
    private ProductStockFlowingService productStockFlowingService;
    @Autowired
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;
    @Autowired
    private OrderRakutenDao orderRakutenDao;
    @Autowired
    private OrderAmazonDao orderAmazonDao;
    @Autowired
    private OrderShopifyDao orderShopifyDao;

    @Override
    public SingleResult addInit(Long userId, Long companyId) {
        return orderInputService.pageInit(userId, companyId);
    }

    @Override
    public Object add(Object req, Long userId) {
        ProductOutDo entityDo = new ProductOutDo();
        BeanUtils.copyProperties(req, entityDo);
        handlerAddBefore(entityDo, userId);
        dao.insert(entityDo);
        return handlerAddAfter(entityDo);
    }

    //新增校验
    private void addCheck(Object req) {

    }

    //做新增之前要执行的业务定制处理
    private void handlerAddBefore(ProductOutDo entityDo, Long userId) {
    }

    //将新增的do转换成要返回的实体
    private Object handlerAddAfter(ProductOutDo entityDo) {
        Object res = new Object();
        BeanUtils.copyProperties(entityDo, res);
        return res;
    }

    @Override
    public SingleResult updateInit(Long id) {
        return SingleResult.success("");
    }

    @Override
    public Object update(Object req, Long userId) {
        /*ProductOutDo entityDo = dao.selectById(req.getId());
        BeanUtils.copyProperties(req, entityDo);
        handlerUpdateBefore(entityDo, userId);
        dao.updateById(entityDo);
        return handlerUpdateAfter(entityDo);*/
        return null;
    }

    //编辑校验
    private void updateCheck(Object req) {

    }

    //做修改之前要执行的业务定制处理
    private void handlerUpdateBefore(ProductOutDo entityDo, Long userId) {

    }

    //做修改之后要执行的业务定制处理
    private Object handlerUpdateAfter(ProductOutDo entityDo) {
        Object res = new Object();
        BeanUtils.copyProperties(entityDo, res);
        return res;
    }

    @Override
    public int delete(Long id, Long userId) {
        ProductOutDo entityDo = dao.selectById(id);
        handlerDeleteBefore(entityDo, userId);
        return dao.deleteById(id);
    }

    //做删除之前要执行的业务定制处理
    private void handlerDeleteBefore(ProductOutDo entityDo, Long userId) {

    }

    @Override
    public Object detail(Long id) {
        ProductOutDo entityDo = dao.selectById(id);
        Object res = new Object();
        BeanUtils.copyProperties(entityDo, res);
        return handlerDetailAfter(res);
    }

    //查询明细之后要执行的业务定制处理
    private Object handlerDetailAfter(Object res) {
        return res;
    }

    @Override
    public SingleResult pageInit() {
        return SingleResult.success("");
    }

    @Override
    public List<Object> getList(Map<String, String> map) {
        QueryWrapper<ProductOutDo> wrapper = queryBuild(map);
        List<ProductOutDo> list = this.list(wrapper);
        List<Object> result = handlerListAfter(list);
        return result;
    }

    @Override
    public PageResult getListPage(Map<String, String> map) {
        IPage<ProductOutDto> page = pageInitDto(map);
        page = dao.getListPage(page, map);
        List<ProductOutRes> list = handlerListAfterDto(page.getRecords(), map.get("timeType"));
        PageResult result = new PageResult(list, (int) page.getCurrent(), (int) page.getSize(), (int) page.getTotal(), (int) page.getPages());
        return result;
    }

    //查询分页列表之后对列表数据的处理
    private List<Object> handlerListAfter(List<ProductOutDo> list) {
        List<Object> result = new ArrayList<>();
        return result;
    }

    private final String productOutRate = "product_out_avg_rate_";

    private List<ProductOutRes> handlerListAfterDto(List<ProductOutDto> list, String timeType) {
        List<ProductOutRes> result = new ArrayList<>();
        for (ProductOutDto record : list) {
            ProductOutRes res = new ProductOutRes();
            BeanUtils.copyProperties(record, res);
            if ("week".equals(timeType)) {//将date 2022-33 转成 2022-07-04-2022-07-10
                WeekFields weekFields = WeekFields.ISO;
                LocalDate now = LocalDate.now();
                //输入你想要的年份和周数
                LocalDate localDate = now.withYear(Integer.parseInt(record.getDate().split("-")[0])).with(weekFields.weekOfYear(), Integer.parseInt(record.getDate().split("-")[1]));
                LocalDate localDate1 = localDate.with(weekFields.dayOfWeek(), 1L);
                LocalDate localDate7 = localDate.with(weekFields.dayOfWeek(), 7L);

                DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd");
                String dateStr1 = localDate1.format(fmt);
                String dateStr7 = localDate7.format(fmt);
                res.setDate(dateStr1 + "-" + dateStr7);
            }
            res.setInitialDate(record.getDate());
            res.setTimeType(timeType);


            //计算权重平均美金汇率
            String key = productOutRate + timeType + "_" + record.getDate();
            Object usdRate = redisTemplate.opsForValue().get(key);
            if (usdRate == null) {
                Double averageUsdRate = dao.getAverageUsdRate(timeType, res.getInitialDate());
                if (averageUsdRate == null) {
                    averageUsdRate = 0D;
                }
                res.setUsdRate(averageUsdRate);
                //放入redis 时间 随机 7-15个小时
                redisTemplate.opsForValue().set(key, averageUsdRate, 60L * 60L * MathUtils.random(7, 15), TimeUnit.SECONDS);
            }
            else {
                res.setUsdRate((Double) usdRate);
            }

            //店铺
            ShopDo shopDo = shopDao.selectById(record.getShopId());
            if (shopDo != null) {
                res.setShopName(shopDo.getShopName());
            }
            result.add(res);
        }
        return result;
    }

    private IPage<ProductOutDo> pageInit(Map<String, String> map) {
        IPage<ProductOutDo> page = new Page();
        page.setSize(StringUtils.isNotBlank(map.get("pageSize")) ? Long.parseLong(map.get("pageSize")) : 10);
        page.setCurrent(StringUtils.isNotBlank(map.get("current")) ? Long.parseLong(map.get("current")) : 1);
        return page;
    }

    private IPage<ProductOutDto> pageInitDto(Map<String, String> map) {
        IPage<ProductOutDto> page = new Page();
        page.setSize(StringUtils.isNotBlank(map.get("pageSize")) ? Long.parseLong(map.get("pageSize")) : 10);
        page.setCurrent(StringUtils.isNotBlank(map.get("current")) ? Long.parseLong(map.get("current")) : 1);
        return page;
    }

    private QueryWrapper<ProductOutDo> queryBuild(Map<String, String> map) {
        QueryWrapper<ProductOutDo> wrapper = new QueryWrapper<>();
        if (StringUtils.isNotBlank(map.get("keyword"))) {
            wrapper.like("keyword", map.get("keyword"));
        }
        return wrapper;
    }


    @Override
    public double getRate(String type) {
        double rate = 0d;
        if ("jpyRate".equals(type)) {
            if (redisTemplate.opsForValue().get("jpyRate") == null) {
                String url = "http://api.k780.com/?app=finance.rate_cnyquot&curno=JPY&&appkey=45417&sign=fa1e01ee26c61537f590e6a543303b18&format=json";
                String body = OkHttpUtils.okHttpRequestPost(url, HttpMethod.POST.name(), "");
                FianceChinaBankVo fianceChinaBank = JSONObject.parseObject(body, FianceChinaBankVo.class);
                rate = Double.parseDouble(fianceChinaBank.getResult().getJPY().getBOC().getMiddle()) / 100;
                redisTemplate.opsForValue().set("jpyRate", rate, 60 * 60 * 12 - 100, TimeUnit.SECONDS);
            } else {
                rate = (Double.parseDouble(redisTemplate.opsForValue().get("jpyRate").toString()));
            }
        } else if ("usdRate".equals(type)) {
            if (redisTemplate.opsForValue().get("usdRate") == null) {
                String url1 = "http://api.k780.com/?app=finance.rate_cnyquot&curno=USD&&appkey=45417&sign=fa1e01ee26c61537f590e6a543303b18&format=json";
                String body1 = OkHttpUtils.okHttpRequestPost(url1, HttpMethod.POST.name(), "");
                FianceChinaBankVo fianceChinaBank1 = JSONObject.parseObject(body1, FianceChinaBankVo.class);
                rate = Double.parseDouble(fianceChinaBank1.getResult().getUSD().getBOC().getCn_sell()) / 100;
                redisTemplate.opsForValue().set("usdRate", rate, 60 * 60 * 12 - 100, TimeUnit.SECONDS);
            } else {
                rate = Double.parseDouble(redisTemplate.opsForValue().get("usdRate").toString());
            }
        }
        return rate;
    }

    @Override
    public List<String> importOrderOut(MultipartFile file, Long shopId, Long companyId, Long useId) throws IOException {
        if (companyId == null) {
            companyId = 1L;
        }
        if (file == null) {
            throw new BizException(SysConstant.Pls_Choose_File);
        }
        if (StringUtils.isBlank(file.getName())) {
            throw new BizException(SysConstant.File_Name_Null);
        }
        String suffix = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf(".") + 1);
        if (!GlobalConstants.IMG_TYPE_XLS.equals(suffix.toUpperCase()) &&
                !GlobalConstants.IMG_TYPE_XLSX.equals(suffix.toUpperCase())) {
            throw new BizException(SysConstant.File_Form_Incorrect);
        }
        List<ProductOutImportVo> exportVoList = new ArrayList<>();
        XSSFWorkbook xssfWorkbook = new XSSFWorkbook(file.getInputStream());
        XSSFSheet sheetAt = xssfWorkbook.getSheetAt(0);

        XSSFRow headerRow = sheetAt.getRow(0); //表头行

        Map<String, Integer> index = new HashMap<>();

        for (int i = 0; i < headerRow.getLastCellNum(); i++) {
            if ("平台".equals(headerRow.getCell(i).getStringCellValue())) {
                index.put("0", i);
            } else if ("订单类型".equals(headerRow.getCell(i).getStringCellValue())) {
                index.put("1", i);
            } else if ("仓库名称".equals(headerRow.getCell(i).getStringCellValue())) {
                index.put("2", i);
            } else if ("参考编号".equals(headerRow.getCell(i).getStringCellValue())) {
                index.put("3", i);
            } else if ("创建时间".equals(headerRow.getCell(i).getStringCellValue())) {
                index.put("4", i);
            } else if ("审核时间".equals(headerRow.getCell(i).getStringCellValue())) {
                index.put("5", i);
            } else if ("发货时间".equals(headerRow.getCell(i).getStringCellValue())) {
                index.put("6", i);
            } else if ("订单金额".equals(headerRow.getCell(i).getStringCellValue())) {
                index.put("7", i);
            } else if ("sku1".equals(headerRow.getCell(i).getStringCellValue())) {
                index.put("8", i);
            } else if ("数量1".equals(headerRow.getCell(i).getStringCellValue())) {
                index.put("9", i);
            }
        }

        if (index.size() < 10) {
            throw new BizException(SysConstant.File_Import_HeaderNotMatch);
        }


        int lastRowNum = sheetAt.getLastRowNum();
        for (int i = 1; i <= lastRowNum; i++) {
            XSSFRow row = sheetAt.getRow(i);
            ProductOutImportVo importVo = new ProductOutImportVo();
            importVo.setPlatform(row.getCell(index.get("0")).getStringCellValue());
            if (row.getCell(index.get("1")) != null && StringUtils.isNotBlank(row.getCell(index.get("1")).getStringCellValue())) {
                importVo.setOrderType(row.getCell(index.get("1")).getStringCellValue());
            }
            if (row.getCell(index.get("2")) != null && StringUtils.isNotBlank(row.getCell(index.get("2")).getStringCellValue())) {
                importVo.setStorageName(row.getCell(index.get("2")).getStringCellValue());
            }
            if (row.getCell(index.get("3")) != null && StringUtils.isNotBlank(row.getCell(index.get("3")).getStringCellValue())) {
                importVo.setOutNo(row.getCell(index.get("3")).getStringCellValue());
            }
            if (row.getCell(index.get("4")) != null && StringUtils.isNotBlank(row.getCell(index.get("4")).getStringCellValue())) {
                importVo.setCreateTime(DateUtils.stringFormatToDateHms(row.getCell(index.get("4")).getStringCellValue()));
            }
            if (row.getCell(index.get("5")) != null && StringUtils.isNotBlank(row.getCell(index.get("5")).getStringCellValue())) {
                importVo.setExamineTime(DateUtils.stringFormatToDateHms(row.getCell(index.get("5")).getStringCellValue()));
            }
            if (row.getCell(index.get("6")) != null && StringUtils.isNotBlank(row.getCell(index.get("6")).getStringCellValue())) {
                importVo.setShippingTime(DateUtils.stringFormatToDateHms(row.getCell(index.get("6")).getStringCellValue()));
            }
            if (row.getCell(index.get("7")) != null) {
                row.getCell(index.get("7")).setCellType(CellType.STRING);
                if (StringUtils.isNotBlank(row.getCell(index.get("7")).getStringCellValue())) {
                    importVo.setOrderAmount(Double.parseDouble(row.getCell(index.get("7")).getStringCellValue()));
                }
            }
            if (row.getCell(index.get("8")) != null && StringUtils.isNotBlank(row.getCell(index.get("8")).getStringCellValue())) {
                importVo.setSku(row.getCell(index.get("8")).getStringCellValue());
            }
            if (row.getCell(index.get("9")) != null) {
                row.getCell(index.get("9")).setCellType(CellType.STRING);
                if (StringUtils.isNotBlank(row.getCell(index.get("9")).getStringCellValue())) {
                    importVo.setQuantity(Integer.parseInt(row.getCell(index.get("9")).getStringCellValue()));
                }
            }
            importVo.setIndex(i + 1);
            exportVoList.add(importVo);
        }


        if (exportVoList.size() > 10000) {
            throw new BizException(SysConstant.File_Import_ToMuch, 10000);
        }
        if (exportVoList.size() == 0) {
            throw new BizException(SysConstant.File_Import_Content);
        }
        //存放错误精确信息
        List<String> msgList = new ArrayList<>();
        exportVoList.sort(new Comparator<ProductOutImportVo>() {
            @Override
            public int compare(ProductOutImportVo o1, ProductOutImportVo o2) {
                if (o1.getShippingTime() == null) {
                    return -1;
                } else if (o2.getShippingTime() == null) {
                    return 1;
                }
                if (o1.getShippingTime().getTime() > o2.getShippingTime().getTime()) {
                    return 1;
                } else if (o1.getShippingTime().getTime() < o2.getShippingTime().getTime()) {
                    return -1;
                } else {
                    return 0;
                }
            }
        });

        Date date = new Date();
        for (int i = 0; i < exportVoList.size(); i++) {
            ProductOutImportVo importVo = exportVoList.get(i);
            if (importVo.getShippingTime() == null || StringUtils.isBlank(importVo.getSku())) {
                continue;
            }
            ProductOutDo et = new ProductOutDo();
            BeanUtils.copyProperties(importVo, et);
            et.setImportBy(useId);
            et.setImportTime(date);
            et.setShopId(shopId);
            et.setCompanyId(companyId);
            et.setJpyRate(this.getRate("jpyRate"));
            et.setUsdRate(this.getRate("usdRate"));


            //获取仓库
            List<StorageDo> storageDoList = storageDao.selectList(new LambdaQueryWrapper<StorageDo>()
                    .eq(StorageDo::getStorageName, importVo.getStorageName()));
            if (storageDoList.size() == 0) {
                msgList.add(String.format(StringsUtil.createI18Message(SysConstant.ProductOut_Import_Storage), importVo.getIndex(), importVo.getStorageName()));
                continue;
            } else if (storageDoList.size() > 1) {
                msgList.add(String.format(StringsUtil.createI18Message(SysConstant.ProductOut_Import_Storage_More), importVo.getIndex(), importVo.getStorageName(), storageDoList.size()));
//                msgList.add("第" + (importVo.getIndex()) + "行,仓库名称:" + importVo.getStorageName() + " 存在 " + storageDoList.size() + "个");
                continue;
            }

            et.setStorageId(storageDoList.get(0).getId());
            if (et.getQuantity() == 0) {
                msgList.add(String.format(StringsUtil.createI18Message(SysConstant.ProductOut_Import_Count), importVo.getIndex(), importVo.getSku()));
//                msgList.add("第" + (importVo.getIndex()) + "行,sku:" + importVo.getSku() + "出库数量为0");
                continue;
            }
            //判断出库单号是否已存在
            ProductOutDo outDo = dao.selectOne(new LambdaQueryWrapper<ProductOutDo>()
                    .eq(ProductOutDo::getOutNo, importVo.getOutNo()).last(" order by id desc limit 1"));
            if (outDo != null) {
                msgList.add(String.format(StringsUtil.createI18Message(SysConstant.ProductOut_Import_HadOut), importVo.getIndex(), importVo.getOutNo()));
//                msgList.add("第" + (importVo.getIndex()) + "行,出库单号:" + importVo.getOutNo() + "已出库,无需再次出库");
                continue;
            }

            //匹配 productId
            Long productId = null;
            try {
                productId = orderOutputService.getProductId(importVo.getSku(), companyId, 2);
            } catch (Exception e) {
                e.printStackTrace();
            }
            if (productId == null) {
                msgList.add(String.format(StringsUtil.createI18Message(SysConstant.ProductOut_Import_Sku), importVo.getIndex(), importVo.getSku()));
//                msgList.add("第" + (importVo.getIndex()) + "行,sku:" + importVo.getSku() + "未匹配");
                continue;
            }

            ProductInfoDo productInfoDo = productInfoDao.selectById(productId);
            if (productInfoDo == null) {
                throw new BizException(SysConstant.Product_NotExist);
            }

            et.setProductId(productId);
            //根据productId 去匹配库存
            int count = et.getQuantity();
            //判断库存够不够
            int total = productStockDao.selectList(new LambdaQueryWrapper<ProductStockDo>()
                    .eq(ProductStockDo::getProductId, productId)
                    .eq(ProductStockDo::getStorageId, storageDoList.get(0).getId())
                    .eq(ProductStockDo::getCompanyId, companyId)
//                    .eq(ProductStockDo::getShopId, shopId)
                    .gt(ProductStockDo::getGoodQuantity, 0)).stream().mapToInt(ProductStockDo::getGoodQuantity).sum();
            ShopDo shopDo = shopDao.selectById(shopId);
            if (shopDo == null) {
                throw new BizException(SysConstant.Shop_NotExist);
            }
            if (total < count) {
                msgList.add(String.format(StringsUtil.createI18Message(SysConstant.ProductOut_Import_Stock), importVo.getIndex(), shopDo.getShopName(), importVo.getSku()));
//                msgList.add("第" + (importVo.getIndex()) + "行,店铺 ：" + shopDo.getShopName() + ",sku:" + importVo.getSku() + "库存不足");
                continue;
            }
            double cost = 0d;
            List<ProductOutRecordDo> recordDos = new ArrayList<>();
            while (count > 0) {
                ProductStockDo stockDo = productStockDao.selectOne(new LambdaQueryWrapper<ProductStockDo>()
                        .eq(ProductStockDo::getProductId, productId)
                        .eq(ProductStockDo::getStorageId, storageDoList.get(0).getId())
                        .eq(ProductStockDo::getCompanyId, companyId)
//                        .eq(ProductStockDo::getShopId, shopId)
                        .gt(ProductStockDo::getGoodQuantity, 0)
                        .orderByAsc(ProductStockDo::getCreateTime)
                        .last(" limit 1"));
                if (stockDo == null) {
//                    msgList.add("第" + (importVo.getIndex()) + "行,sku:" + importVo.getSku() + "库存不足");
                    throw new BizException(SysConstant.ProductOut_Import_Stock_Error, importVo.getIndex(), shopDo.getShopName(), importVo.getSku());
                }
                StockMsgRes res = this.dealWithOneStock(count, stockDo, cost, productInfoDo, shopId, useId, importVo.getOutNo(), true);
                count = res.getCount();
                cost = MathUtils.add(cost, MathUtils.mul(orderInputService.getOrderInputUnitCost(stockDo.getOrderId(), companyId), productInfoDo.getLength(), productInfoDo.getWidth(), productInfoDo.getHeight(), res.getOnceCount()));

                recordDos.addAll(res.getRecordDoList());
                //扣完t_product_stock表库存 再去扣t_product_stock_rack表库存
                this.dealStockRack(res.getOnceCount(), stockDo.getId());
            }
            et.setUnitCost(MathUtils.div(cost, et.getQuantity()));
            et.setStatus("finish");
            dao.insert(et);
            for (ProductOutRecordDo recordDo : recordDos) {
                recordDo.setOutId(et.getId());
                recordDo.setType("out");
                productOutRecordDao.insert(recordDo);
            }

        }

        return msgList;
    }


    /**
     * 操作库存 并添加 t_product_out 表记录, 这个方法之前就处理过 stockRack表库存
     *
     * @param productId
     * @param storageId
     * @param shopId
     * @param companyId
     * @param useId
     * @param count
     * @param outOrderNo
     * @param platform
     * @param orderType
     * @param omsFlag
     */
    @Override
    public void dealWithStock(Long stockId, Long productId, Long storageId, Long shopId, Long companyId, Long useId,
                              int count, String systemOutOrderNo, String outOrderNo, String platform, String orderType, boolean omsFlag) {

        if (StringUtils.isBlank(systemOutOrderNo)) {
            throw new BizException(SysConstant.Pls_Fill_OutOrderNo);
        }
        ProductInfoDo productInfoDo = productInfoDao.selectById(productId);
        if (productInfoDo == null) {
            throw new BizException(SysConstant.Product_NotExist);
        }

        List<ProductOutRecordDo> recordDos = new ArrayList<>();

        ProductStockDo stockDo = productStockDao.selectById(stockId);

        if (stockDo == null || stockDo.getGoodQuantity() < count) {
            throw new BizException(SysConstant.Product_Stock_NotEnough, productInfoDo.getCommoditySku());
        }
        StockMsgRes res = this.dealWithOneStock(count, stockDo, 0d, productInfoDo, shopId, useId, outOrderNo, omsFlag);
//        count = res.getCount();
        recordDos.addAll(res.getRecordDoList());
        //}

        threadPoolTaskExecutor.execute(() -> {
            ProductOutDo et = new ProductOutDo();
            et.setOutNo(systemOutOrderNo);
            et.setPlatform(platform);
            et.setOrderType(orderType);
            et.setCreateTime(new Date());
            et.setShippingTime(new Date());
            et.setQuantity(count);
            et.setProductId(productId);

            et.setImportBy(useId);
            et.setImportTime(new Date());
            et.setShopId(shopId);
            et.setStorageId(storageId);
            et.setCompanyId(companyId);
            et.setJpyRate(this.getRate("jpyRate"));
            et.setUsdRate(this.getRate("usdRate"));


            et.setSku(productInfoDo.getCommoditySku());
            double cost = MathUtils.mul(orderInputService.getOrderInputUnitCost(stockDo.getOrderId(), companyId), productInfoDo.getLength(), productInfoDo.getWidth(), productInfoDo.getHeight(), res.getOnceCount());

            et.setUnitCost(MathUtils.div(cost, et.getQuantity()));
            et.setStatus("finish");
            dao.insert(et);
            for (ProductOutRecordDo recordDo : recordDos) {
                recordDo.setOutId(et.getId());
                recordDo.setType(platform);
                productOutRecordDao.insert(recordDo);
            }
        });

    }


    public StockMsgRes dealWithOneStock(int count, ProductStockDo stockDo, double cost, ProductInfoDo productInfoDo, Long shopId, Long useId, String outOrderNo, Boolean omsFlag) {

        StockMsgRes res = new StockMsgRes();
        Integer onceCount = 0;
        if (stockDo.getGoodQuantity() >= count) {
            onceCount = count;
            count = 0;

        } else {
            onceCount = stockDo.getGoodQuantity();
            count -= stockDo.getGoodQuantity();
        }
//        stockDo.setGoodQuantity(stockDo.getGoodQuantity() - onceCount);
//        productStockDao.updateById(stockDo);//更新库存
        productStockDao.updateStockById(stockDo.getId(), onceCount);//更新库存

        res.setCount(count);
        res.setOnceCount(onceCount);

        List<ProductOutRecordDo> recordDos = new ArrayList<>();
        ProductOutRecordDo recordDo = new ProductOutRecordDo();
        recordDo.setQuantity(onceCount);
        recordDo.setStockId(stockDo.getId());
        recordDos.add(recordDo);
        res.setRecordDoList(recordDos);

        if (omsFlag) {
            //扣减旧表库存
            stockRecordService.deduceGoodStock(productInfoDo, stockDo.getStorageId(), shopId, onceCount, outOrderNo, useId);
        }
        //判断新库存表 是否需要删除
//        if (stockDo.getGoodQuantity() <= 0 && stockDo.getBadQuantity() <= 0) {
//            productStockDao.deleteById(stockDo);
//        }
        return res;

    }


    //出库操作完 t_product_stock 后 再去操作 t_product_stock_rack 表
    public void dealStockRack(int onceCount, Long stockId) {
        List<ProductStockRackDo> rackDoList = productStockRackDao.selectList(new LambdaQueryWrapper<ProductStockRackDo>()
                .eq(ProductStockRackDo::getStockId, stockId).orderByDesc(ProductStockRackDo::getRackId));
        int total = rackDoList.stream().mapToInt(ProductStockRackDo::getGoodQuantity).sum();
        if (total < onceCount) {
            throw new BizException(SysConstant.Order_StockRack_NotEnough);
        }

        for (ProductStockRackDo rackDo : rackDoList) {
            Map<String, Integer> resultMap = productStockRackService.dealWithOneRackStock(onceCount, 0, rackDo, "out", null, "出库成本导入出库单", null);
            onceCount = resultMap.get("goodQuantity");
            if (onceCount <= 0) {
                break;
            }
        }

    }


    private IPage<ProductOutDetailDto> pageInitDetailDto(Map<String, String> map) {
        IPage<ProductOutDetailDto> page = new Page();
        page.setSize(StringUtils.isNotBlank(map.get("pageSize")) ? Long.parseLong(map.get("pageSize")) : 10);
        page.setCurrent(StringUtils.isNotBlank(map.get("current")) ? Long.parseLong(map.get("current")) : 1);
        return page;
    }

    @Override
    public PageResult getOutDetail(Long shopId, String timeType, String initialDate, String skuEq, String keyword, int current, int pageSize) {
        Map<String, String> map = new HashMap<>();
        map.put("timeType", timeType);
        if (StringUtils.isNotBlank(skuEq)) {
            map.put("skuEq", skuEq);
        }
        if (shopId != null) {
            map.put("shopId", shopId + "");
        }
        if (StringUtils.isNotBlank(keyword)) {
            map.put("keyword", keyword);
        }
        map.put("current", current + "");
        map.put("pageSize", pageSize + "");
        IPage<ProductOutDetailDto> page = pageInitDetailDto(map);
        page = dao.getDetailList(page, map, Arrays.asList(initialDate));
        List<ProductOutDetailRes> resList = this.getDetailRes(page.getRecords());
        PageResult result = new PageResult(resList, (int) page.getCurrent(), (int) page.getSize(), (int) page.getTotal(), (int) page.getPages());
        List<ProductOutDetailDto> allList = dao.getDetailList(map, Arrays.asList(initialDate));
        result.setMapInfo(this.getMapInfo(allList, shopId));
        return result;
    }


    public List<ProductOutShopRes> getOutDetail(Map<String, String> map, List<String> initialDateList) {
        List<ProductOutDetailDto> list = dao.getDetailList(map, initialDateList);
        return this.hanlderOutDetail(list);
    }

    public List<ProductOutDetailRes> getDetailRes(List<ProductOutDetailDto> list) {
        List<ProductOutDetailRes> resList = new ArrayList<>();
        for (ProductOutDetailDto productOutDetailDto : list) {
            //计算总成本
            ProductOutDetailRes res = new ProductOutDetailRes();
            BeanUtils.copyProperties(productOutDetailDto, res);
            //单位入库成本是美金，一开始 总成本是rmb 后来改成usd
            res.setCost(MathUtils.add(productOutDetailDto.getUsdReportPrice(), MathUtils.mul(productOutDetailDto.getUnitCost(), productOutDetailDto.getQuantity())));
            res.setCost(MathUtils.numberFormat(res.getCost()));
            resList.add(res);
        }
        return resList;
    }

    public List<ProductOutShopRes> hanlderOutDetail(List<ProductOutDetailDto> list) {
        List<ProductOutDetailRes> resList = this.getDetailRes(list);
        Map<Long, List<ProductOutDetailRes>> listMap = resList.stream().collect(Collectors.groupingBy(ProductOutDetailRes::getShopId));
        Set<Long> keyList = listMap.keySet();
        List<ProductOutShopRes> shopResList = new ArrayList<>();
        for (Long shopId : keyList) {
            ShopDo shopDo = shopDao.selectById(shopId);
            if (shopDo == null) {
                continue;
            }
            ProductOutShopRes res = new ProductOutShopRes();
            res.setShopId(shopId);
            res.setShopName(shopDo.getShopName());
            res.setTotalQuantity(listMap.get(shopId).stream().mapToInt(ProductOutDetailRes::getQuantity).sum());
            res.setTotalCost(MathUtils.numberFormat(listMap.get(shopId).stream().mapToDouble(ProductOutDetailRes::getCost).sum()));
            res.setList(listMap.get(shopId));
            shopResList.add(res);
        }
        return shopResList;
    }

    public List<ProductOutShopRes> getOutDetail(Long shopId, String timeType, List<String> initialDateList) {
        Map<String, String> map = new HashMap<>();
        map.put("timeType", timeType);
        if (shopId != null) {
            map.put("shopId", shopId + "");
        }
        return this.getOutDetail(map, initialDateList);
    }


    /**
     * SKU维度
     *
     * @param timeType
     * @param initialDateList
     * @return
     */
    @Override
    public PageResult getOutDetailBySku(Long shopId, String timeType, List<String> initialDateList, String keyword, int current, int pageSize) {
        Map<String, String> map = new HashMap<>();
        map.put("timeType", timeType);
        if (shopId != null) {
            map.put("shopId", shopId + "");
        }
        if (StringUtils.isNotBlank(keyword)) {
            map.put("keyword", keyword);
        }
        map.put("current", current + "");
        map.put("pageSize", pageSize + "");
        IPage<ProductOutDetailDto> page = this.pageInitDetailDto(map);
        page = dao.getDetailListBySku(page, map, initialDateList);
        List<ProductOutDetailRes> resList = this.getDetailRes(page.getRecords());
//        List<ProductOutDetailDto> list = dao.getDetailListBySku(map, initialDateList);
        PageResult result = new PageResult(resList, (int) page.getCurrent(), (int) page.getSize(), (int) page.getTotal(), (int) page.getPages());
        List<ProductOutDetailDto> allList = dao.getDetailListBySku(map, initialDateList);
        result.setMapInfo(this.getMapInfo(allList, shopId));
        return result;
    }

    public Map getMapInfo(List<ProductOutDetailDto> allList, Long shopId) {
        Map mapInfo = new HashMap();

        int quantity = allList.stream().mapToInt(ProductOutDetailDto::getQuantity).sum();
        double cost = allList.stream().mapToDouble(i -> i.getUnitCost() * i.getQuantity() + i.getUsdReportPrice()).sum();
        mapInfo.put("totalQuantity", quantity);
        mapInfo.put("totalCost", MathUtils.numberFormat(cost, 6));
        ShopDo shopDo = shopDao.selectById(shopId);
        if (shopDo != null) {
            mapInfo.put("shopName", shopDo.getShopName());
        }
        return mapInfo;
    }


    @Override
    public void export(ProductOutExportReq req, HttpServletResponse response) throws IOException {
        List<ProductOutExportVo> exportVoList = new ArrayList<>();
        List<ProductOutShopRes> resList = this.getOutDetail(req.getShopId(), req.getTimeType(), req.getInitialDateList());
        for (ProductOutShopRes res : resList) {
            for (ProductOutDetailRes productOutDetailRes : res.getList()) {
                ProductOutExportVo exportVo = new ProductOutExportVo();
                BeanUtils.copyProperties(productOutDetailRes, exportVo);
                exportVo.setShopName(res.getShopName());
                exportVoList.add(exportVo);
            }

        }
        ExcelUtils.exportExcel(exportVoList, ProductOutExportVo.class, "出库详情.xlsx", new ExportParams(), response);
    }


    /**
     * 导出总览
     *
     * @param req
     * @param response
     * @throws IOException
     */
    @Override
    public void exportOverView(ProductOutExportReq req, HttpServletResponse response) throws IOException {
        List<ProductOutOverViewExportVo> exportVoList = new ArrayList<>();

        Map<String, String> map = new HashMap<>();
        map.put("timeType", req.getTimeType());
        if (req.getShopId() != null) {
            map.put("shopId", req.getShopId() + "");
        }
        List<ProductOutDetailDto> list = dao.getDetailListBySku(map, req.getInitialDateList());
        List<ProductOutShopRes> resList = this.hanlderOutDetail(list);
        for (ProductOutShopRes res : resList) {
            for (ProductOutDetailRes productOutDetailRes : res.getList()) {
                ProductOutOverViewExportVo exportVo = new ProductOutOverViewExportVo();
                BeanUtils.copyProperties(productOutDetailRes, exportVo);
                exportVo.setShopName(res.getShopName());
                exportVoList.add(exportVo);
            }

        }
        ExcelUtils.exportExcel(exportVoList, ProductOutOverViewExportVo.class, "出库总览.xlsx", new ExportParams(), response);
    }


    /**
     * 按天按sku导出 库存
     */
    @Override
    public void exportStockLog(ProductOutExportReq req, HttpServletResponse response) throws IOException {
        if (req.getInitialDateList().size() == 0) {
            throw new BizException(SysConstant.Pls_Choose_Data);
        }
        String timeStr = null;
        String lastTimeStr = null;
        //获取期初日期
        if ("week".equals(req.getTimeType())) {
            WeekFields weekFields = WeekFields.ISO;
            LocalDate now = LocalDate.now();
            //输入你想要的年份和周数
            LocalDate localDate = now.withYear(Integer.parseInt(req.getInitialDateList().get(req.getInitialDateList().size() - 1).split("-")[0])).with(weekFields.weekOfYear(), Integer.parseInt(req.getInitialDateList().get(req.getInitialDateList().size() - 1).split("-")[1]));
            LocalDate localDate1 = localDate.with(weekFields.dayOfWeek(), 1L);
            LocalDate localDate7 = localDate.with(weekFields.dayOfWeek(), 7L);

            //周开始时间
            DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd");
            String dateStr1 = localDate1.format(fmt);
//            String dateStr7 = localDate7.format(fmt);
            timeStr = dateStr1;

            //周最后一天
            LocalDate firstLocalDate = now.withYear(Integer.parseInt(req.getInitialDateList().get(0).split("-")[0])).with(weekFields.weekOfYear(), Integer.parseInt(req.getInitialDateList().get(0).split("-")[1]));
            LocalDate firstLocalDate7 = firstLocalDate.with(weekFields.dayOfWeek(), 7L);
            lastTimeStr = firstLocalDate7.format(fmt);

        } else {
            timeStr = req.getInitialDateList().get(req.getInitialDateList().size() - 1) + "-01";
            lastTimeStr = DateUtils.dateFormatToString(DateUtils.getEndDayOrOneDay(DateUtils.stringFormatToDate(req.getInitialDateList().get(0), "yyyy-MM"), 1, 0));
        }
        Map<String, String> param1 = new HashMap<>();
        param1.put("timeStr", timeStr);
        if (req.getShopId() != null) {
            param1.put("shopId", req.getShopId() + "");
        }
        //期初库存
        List<ProductOutStockDto> leftStockList = dao.getLeftStockByDate(param1);
//        Map<String, List<ProductOutStockDto>> leftStockListMap = leftStockList.stream().collect(Collectors.groupingBy(ProductOutStockDto::getSku));
        //出入库记录

        Map<String, String> param2 = new HashMap<>();
        param2.put("timeType", req.getTimeType());
        if (req.getShopId() != null) {
            param2.put("shopId", req.getShopId() + "");
        }
        List<ProductOutStockDto> stockLogList = dao.getStockLogByDate(param2, req.getInitialDateList());
        List<ProductOutStockLogExportVo> exportVoList = new ArrayList<>();

        Map<String, Integer> stockMap = new HashMap<>();
        Map<String, Float> skuPriceMap = new HashMap<>();

        for (ProductOutStockDto productOutStockDto : leftStockList) {
            ProductOutStockLogExportVo exportVo = new ProductOutStockLogExportVo();
            BeanUtils.copyProperties(productOutStockDto, exportVo);
            exportVoList.add(exportVo);
            stockMap.merge(productOutStockDto.getSku(), productOutStockDto.getBalance(), Integer::sum);
            skuPriceMap.put(productOutStockDto.getSku(), productOutStockDto.getPrice());
        }
        for (ProductOutStockDto productOutStockDto : stockLogList) {
            ProductOutStockLogExportVo exportVo = new ProductOutStockLogExportVo();
            BeanUtils.copyProperties(productOutStockDto, exportVo);
            //计算结余数量
            if ("入库".equals(productOutStockDto.getType())) {
                //入库
                stockMap.merge(productOutStockDto.getSku(), productOutStockDto.getInQuantity(), Integer::sum);
            } else if ("出库".equals(productOutStockDto.getType())) {
                stockMap.merge(productOutStockDto.getSku(), -productOutStockDto.getOutQuantity(), Integer::sum);
            }
            skuPriceMap.put(productOutStockDto.getSku(), productOutStockDto.getPrice());
            exportVo.setBalance(stockMap.get(productOutStockDto.getSku()));
            //结余金额
            exportVo.setAmount3(productOutStockDto.getPrice() * exportVo.getBalance());
            exportVoList.add(exportVo);
        }
        //加入结余数量
        for (String sku : stockMap.keySet()) {
            ProductOutStockLogExportVo exportVo = new ProductOutStockLogExportVo();
            exportVo.setDate(lastTimeStr);
            exportVo.setSku(sku);
            exportVo.setType("期末结余");
            exportVo.setBalance(stockMap.get(sku));
            exportVo.setPrice(skuPriceMap.get(sku));
            exportVo.setPrice2(skuPriceMap.get(sku));
            exportVo.setPrice3(skuPriceMap.get(sku));
            exportVo.setAmount3(skuPriceMap.get(sku) * stockMap.get(sku));

            exportVoList.add(exportVo);
        }
        ExportParams params = new ExportParams();
        ShopDo shopDo = shopDao.selectById(req.getShopId());
        if (shopDo != null) {
            params.setTitle(shopDo.getShopName());
        }

        ExcelUtils.exportExcel(exportVoList, ProductOutStockLogExportVo.class, "出库记录", params, response);
    }


    /**
     * fba出库单 和出库单发货 减库存 (已拣货)
     *
     * @param orderNo
     * @param platform
     * @param orderType
     * @param quantity
     * @param productId
     * @param storageId
     * @param shopId
     * @param pickUpId
     * @param companyId
     * @param userId
     */
    @Override
    public SendRes dealStockAfterSendOut(Long outputId, String orderNo, String platform, String orderType, int quantity, Long productId, Long storageId, Long shopId, Long pickUpId, Long companyId, Long userId) {
        SendRes result = new SendRes();
        //操作新表库存
        ProductInfoDo productInfoDo = productInfoDao.selectById(productId);
        if (productInfoDo == null) {
            result.setCode(500);
            result.setMsg(SysConstant.Product_NotExist);
            return result;
        }
        double cost = 0d;
        List<StockPickUpDetailDo> pickUpDetailDoList = stockPickUpDetailDao.selectList(new LambdaQueryWrapper<StockPickUpDetailDo>()
                .eq(StockPickUpDetailDo::getOrderOutputId, outputId)
                .eq(StockPickUpDetailDo::getPickUpId, pickUpId)
                .eq(StockPickUpDetailDo::getProductId, productId));
        int sum = pickUpDetailDoList.stream().mapToInt(StockPickUpDetailDo::getNumber).sum();
        if (quantity != sum) {
            result.setCode(500);
            result.setMsg(SysConstant.Order_PickCount_NotMatch);
            return result;
        }

        Map<Long, Integer> outRecordMap = new HashMap<>();
        for (StockPickUpDetailDo pickUpDetailDo : pickUpDetailDoList) {
            int goodQuantity = pickUpDetailDo.getNumber();
            //解决 两个出库单 同时锁定一个库存id时，后者多的一个出库单先发货，将锁定库存发完，导致锁定库存不够
            List<ProductStockRackDo> stockRackDoList;
            synchronized (this) {
                ProductStockRackDo stockRackDo = productStockRackDao.getOne(pickUpDetailDo.getStockRackId());
                stockRackDoList = productStockRackDao.getLockingStockList(productId, storageId, stockRackDo.getRackId());
            }
            if (stockRackDoList.stream().mapToInt(ProductStockRackDo::getGoodLockQuantity).sum() < goodQuantity) {
                result.setCode(500);
                result.setMsg(SysConstant.Order_LockCount_NotEnough);
                return result;
            }
            for (ProductStockRackDo rackDo : stockRackDoList) {
                DealStockRackRes res = this.dealStockRack(rackDo, goodQuantity, outRecordMap, orderNo, orderType, productId, storageId, shopId, companyId, userId);
                if (res.getCode() != 200) {
                    result.setCode(500);
                    result.setMsg(res.getMsg());
                    return result;
                }
                productStockRackDao.updateLockStockById(rackDo.getId(), res.getOnceCount());

                //库存流水新
                productStockFlowingService.insertFlowing(orderType, orderNo, shopId, productId, storageId,
                        0, 0, -res.getOnceCount(), rackDo.getRackId(), companyId, userId, "出库单:"+orderNo+"出库");

                //此记录单纯给 fba出库单回滚用
                if ("fbaOutput".equals(orderType)) {
                    productStockFlowingService.insertFlowing(StaticDict.Product_Flowing_Type.FbaSend.getValue(), orderNo, shopId, productId, storageId,
                            0, 0, -res.getOnceCount(), rackDo.getRackId(), companyId, userId, "fba出库单:"+orderNo+"发货记录");
                }

                goodQuantity = res.getGoodQuantity();
//                cost = res.getCost();
                if (goodQuantity <= 0) {
                    break;
                }
            }
            if (goodQuantity > 0) {
//                throw new BizException("锁定库存不够");
                result.setCode(500);
                result.setMsg(SysConstant.Order_LockCount_NotEnough);
                return result;
            }
        }

        for (Long stockId : outRecordMap.keySet()) {
            ProductStockDo stockDo;
//        synchronized (this) {
            stockDo = productStockDao.selectById(stockId);
            //}
            if (stockDo == null) {
                result.setCode(500);
                result.setMsg(SysConstant.Order_Stock_NotMatch);
                return result;
            }
//        stockDo.setGoodQuantity(stockDo.getGoodQuantity() - onceCount);
            productStockDao.updateStockById(stockDo.getId(), outRecordMap.get(stockId));
            cost = MathUtils.add(cost, MathUtils.mul(orderInputService.getOrderInputUnitCost(stockDo.getOrderId(), companyId), productInfoDo.getLength(), productInfoDo.getWidth(), productInfoDo.getHeight(), outRecordMap.get(stockId)));

        }

        double finalCost = cost;
        threadPoolTaskExecutor.execute(() -> {
            ProductOutDo et = new ProductOutDo();
            et.setOutNo(orderNo);
            et.setPlatform(platform);
            et.setOrderType(orderType);
            et.setCreateTime(new Date());
            et.setShippingTime(new Date());
            et.setQuantity(quantity);
            et.setProductId(productId);
            et.setImportBy(userId);
            et.setImportTime(new Date());
            et.setShopId(shopId);
            et.setStorageId(storageId);
            et.setCompanyId(companyId);
            et.setJpyRate(this.getRate("jpyRate"));
            et.setUsdRate(this.getRate("usdRate"));

            et.setSku(productInfoDo.getCommoditySku());
            et.setUnitCost(MathUtils.div(finalCost, et.getQuantity()));
            et.setStatus("finish");
            dao.insert(et);

            for (Long stockId : outRecordMap.keySet()) {
                ProductOutRecordDo recordDo = new ProductOutRecordDo();
                recordDo.setOutId(et.getId());
                recordDo.setType(orderType);
                recordDo.setQuantity(outRecordMap.get(stockId));
                recordDo.setStockId(stockId);
                productOutRecordDao.insert(recordDo);
            }
        });
        result.setCode(200);
        return result;
    }


    public DealStockRackRes dealStockRack(ProductStockRackDo stockRackDo, int goodQuantity, Map<Long, Integer> outRecordMap, String orderNo, String orderType, Long productId, Long storageId, Long shopId, Long companyId, Long userId) {
        DealStockRackRes res = new DealStockRackRes();
        res.setCode(200);
        if (stockRackDo.getGoodLockQuantity() <= 0) {
            res.setGoodQuantity(goodQuantity);
//            res.setCost(cost);
            res.setOnceCount(0);
            return res;
        }

        int onceCount = 0;
        if (stockRackDo.getGoodLockQuantity() >= goodQuantity) {
            onceCount = goodQuantity;
            stockRackDo.setGoodLockQuantity(stockRackDo.getGoodLockQuantity() - goodQuantity);
            goodQuantity = 0;
        } else {
            onceCount = stockRackDo.getGoodLockQuantity();
            goodQuantity -= stockRackDo.getGoodLockQuantity();
            stockRackDo.setGoodLockQuantity(0);
        }

        outRecordMap.merge(stockRackDo.getStockId(), onceCount, Integer::sum);
        res.setGoodQuantity(goodQuantity);
//        res.setCost(cost);
        res.setOnceCount(onceCount);
        return res;
    }


    /**
     * 定时器匹配 平台订单时间
     */
    @Override
    public void matchPlatformTime() {
        List<ProductOutDo> list = dao.selectList(new LambdaQueryWrapper<ProductOutDo>().eq(ProductOutDo::getOrderType, "output").isNull(ProductOutDo::getPlatCreateTime));
        for (ProductOutDo et : list) {
            this.matchProductOut(et);
        }
    }


    public void matchPlatformTimeUtils() {
        List<ProductOutDo> list = dao.selectList(new LambdaQueryWrapper<ProductOutDo>().eq(ProductOutDo::getOrderType, "output").isNull(ProductOutDo::getPlatCreateTime)
                .gt(ProductOutDo::getCreateTime, DateUtils.dateFormatToString(DateUtils.passingDate(new Date(), -1), "yyyy-MM-dd HH:mm:ss")));
        for (ProductOutDo et : list) {
            this.matchProductOut(et);
        }
    }



    public void matchProductOut(ProductOutDo et) {
        OrderOutputDo orderOutputDo = orderOutputService.getOne(new LambdaQueryWrapper<OrderOutputDo>().eq(OrderOutputDo::getOrderOutputNumber, et.getOutNo()).last(" order by id desc limit 1"));
        if (orderOutputDo == null) {
            return;
        }
        if ("ecang".equals(orderOutputDo.getPlatform()) || "qianyi".equals(orderOutputDo.getPlatform()) || "yahoo".equals(orderOutputDo.getPlatform()) || "qoo10".equals(orderOutputDo.getPlatform())) {
            //这两个平台不匹配
            return;
        }
        if ("rakuten".equals(orderOutputDo.getPlatform())) {
            //乐天订单
            OrderRakutenDo rakutenDo = orderRakutenDao.selectById(orderOutputDo.getPlatformNumber());
            if (rakutenDo == null) {
                et.setPlatCreateTime(et.getCreateTime());
            }
            else {
                et.setPlatCreateTime(DateUtils.stringFormatToDate(rakutenDo.getOrderDatetime(), "yyyy-MM-dd HH:mm:ss"));
            }
            dao.updateById(et);
        }
        else if ("amazon".equals(orderOutputDo.getPlatform())) {
            OrderAmazonDo orderAmazonDo = orderAmazonDao.selectById(orderOutputDo.getPlatformNumber());
            if (orderAmazonDo == null) {
                et.setPlatCreateTime(et.getCreateTime());
            }
            else {
                et.setPlatCreateTime(orderAmazonDo.getPurchaseDate());
            }
            dao.updateById(et);
        }
        else if ("shopify".equals(orderOutputDo.getPlatform())) {
            OrderShopifyDo orderShopifyDo = orderShopifyDao.selectById(orderOutputDo.getPlatformNumber());
            if (orderShopifyDo == null) {
                et.setPlatCreateTime(et.getCreateTime());
            }
            else {
                et.setPlatCreateTime(orderShopifyDo.getCreatedAt());
            }
            dao.updateById(et);
        }
        else {
            //平台为空的 去 rakuten amazon shopify 三个平台匹配
            OrderAmazonDo orderAmazonDo = orderAmazonDao.selectOne(new LambdaQueryWrapper<OrderAmazonDo>().eq(OrderAmazonDo::getAmazonOrderNumber, orderOutputDo.getOrderNo()).last(" order by id desc limit 1"));
            if (orderAmazonDo != null) {
                et.setPlatCreateTime(orderAmazonDo.getPurchaseDate());
                dao.updateById(et);
                return;
            }

            OrderRakutenDo rakutenDo = orderRakutenDao.selectOne(new LambdaQueryWrapper<OrderRakutenDo>().eq(OrderRakutenDo::getOrderNumber, orderOutputDo.getOrderNo()).last(" order by id desc limit 1"));
            if (rakutenDo != null) {
                et.setPlatCreateTime(DateUtils.stringFormatToDate(rakutenDo.getOrderDatetime(), "yyyy-MM-dd HH:mm:ss"));
                dao.updateById(et);
                return;
            }
            OrderShopifyDo orderShopifyDo = orderShopifyDao.selectOne(new LambdaQueryWrapper<OrderShopifyDo>().eq(OrderShopifyDo::getOrderNumber, orderOutputDo.getOrderNo()).last(" order by id desc limit 1"));
            if (orderShopifyDo != null) {
                et.setPlatCreateTime(orderShopifyDo.getCreatedAt());
                dao.updateById(et);
                return;
            }
            //都没有匹配到
            et.setPlatCreateTime(et.getCreateTime());
            dao.updateById(et);
        }
    }

}
